package com.flying.invest.strategy.service;

import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.flying.common.annotation.DaoCreate;
import com.flying.common.annotation.DaoQuery;
import com.flying.common.annotation.DaoRemove;
import com.flying.common.annotation.DaoUpdate;
import com.flying.common.annotation.Transaction;
import com.flying.common.util.Codes;
import com.flying.common.util.DateUtils;
import com.flying.common.util.DateUtils.Field;
import com.flying.framework.annotation.MethodInfo;
import com.flying.framework.annotation.Param;
import com.flying.framework.annotation.Service;
import com.flying.framework.exception.AppException;
import com.flying.framework.model.ActionResult;
import com.flying.framework.model.ModelFactory;
import com.flying.framework.model.QueryResult;
import com.flying.framework.service.AbstractService;
import com.flying.invest.invest.TransactionType;
import com.flying.invest.invest.model.Investment;
import com.flying.invest.invest.model.InvestmentSuggestion;
import com.flying.invest.invest.service.InvestmentService;
import com.flying.invest.invest.service.InvestmentSuggestionService;
import com.flying.invest.strategy.model.Strategy;
import com.flying.invest.strategy.model.StrategyGrid;
import com.flying.invest.strategy.model.StrategyValueAverage;
import com.flying.invest.strategy.model.StrategyValueAverage.TriggerCondition;

@Service(value="StrategyValueAverageService", desc="价值平均策略")
public class StrategyValueAverageService extends AbstractService implements IStrategyService{
    private InvestmentService investService;
    private StrategyService strategyService;
    private InvestmentSuggestionService suggestionService;
    private StrategyValueAverageDetailService detailService;
    
    public void setInvestmentService(InvestmentService s) {
    	this.investService = s;
    }
    public void setStrategyService(StrategyService s) {
    	this.strategyService = s;
    }
    public void setInvestmentSuggestionService(InvestmentSuggestionService s) {
    	this.suggestionService = s;
    }
    public void setStrategyValueAverageDetailService(StrategyValueAverageDetailService s) {
    	this.detailService = s;
    }
    
	@MethodInfo("新增")
	@DaoCreate(entity=StrategyValueAverage.ENTITY_NAME)
	public StrategyValueAverage create(
			@Param(value=StrategyValueAverage.STRATEGY_ID, required=true,	desc="策略ID") Long strategy_id,
			@Param(value=StrategyValueAverage.TARGET_AMOUNT, required=true,	desc="目标市值") Double target_amount,
			@Param(value=StrategyValueAverage.INFLATION_RATE, required=false,	desc="时间成本率") Double inflation_rate,
			@Param(value=StrategyValueAverage.RISE_AMOUNT, required=false,	desc="上涨金额") Double rise_amount,
			@Param(value=StrategyValueAverage.RISE_RATE, required=false,	desc="上涨比率") Double rise_rate,
			@Param(value=StrategyValueAverage.RISE_COND, required=false,	desc="上升条件", enumClass=TriggerCondition.class) Integer rise_cond,
			@Param(value=StrategyValueAverage.FELL_RATE, required=false,	desc="下跌比率") Double fell_rate,
			@Param(value=StrategyValueAverage.FELL_AMOUNT, required=false,	desc="下跌金额") Double fell_amount,
			@Param(value=StrategyValueAverage.FELL_COND, required=false,	desc="下跌条件", enumClass=TriggerCondition.class) Integer fell_cond
		) {
		
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public StrategyValueAverage createSub(Long strategy_id) {
		return this.create(strategy_id, 0.0, null, 
				0.0, 0.0, TriggerCondition.AMOUNT_OR_RATE.value, 
				0.0, 0.0, TriggerCondition.AMOUNT_OR_RATE.value);
	}

	@MethodInfo("修改")
	@DaoUpdate(entity=StrategyValueAverage.ENTITY_NAME, expectedEffectRows=1)
	public ActionResult update(
			@Param(value=StrategyValueAverage.STRATEGY_ID, required=true,	desc="策略ID") Long strategy_id,
			@Param(value=StrategyValueAverage.TARGET_AMOUNT, required=true,	desc="目标市值") Double target_amount,
			@Param(value=StrategyValueAverage.INFLATION_RATE, required=false,	desc="时间成本率") Double inflation_rate,
			@Param(value=StrategyValueAverage.RISE_AMOUNT, required=false,	desc="上涨金额") Double rise_amount,
			@Param(value=StrategyValueAverage.RISE_RATE, required=false,	desc="上涨比率") Double rise_rate,
			@Param(value=StrategyValueAverage.RISE_COND, required=false,	desc="上升条件", enumClass=TriggerCondition.class) Integer rise_cond,
			@Param(value=StrategyValueAverage.FELL_RATE, required=false,	desc="下跌比率") Double fell_rate,
			@Param(value=StrategyValueAverage.FELL_AMOUNT, required=false,	desc="下跌金额") Double fell_amount,
			@Param(value=StrategyValueAverage.FELL_COND, required=false,	desc="下跌条件", enumClass=TriggerCondition.class) Integer fell_cond
		) throws Exception {
		return null;
	}

	@MethodInfo("修改")
	public ActionResult config(
			@Param(value=StrategyValueAverage.STRATEGY_ID, required=true,	desc="策略ID") Long strategy_id,
			@Param(value=StrategyValueAverage.TARGET_AMOUNT, required=true,	desc="目标市值") Double target_amount,
			@Param(value=StrategyValueAverage.INFLATION_RATE, required=false,	desc="时间成本率") Double inflation_rate,
			@Param(value=StrategyValueAverage.RISE_AMOUNT, required=false,	desc="上涨金额") Double rise_amount,
			@Param(value=StrategyValueAverage.RISE_RATE, required=false,	desc="上涨比率") Double rise_rate,
			@Param(value=StrategyValueAverage.RISE_COND, required=true,	desc="上升条件", enumClass=TriggerCondition.class) Integer rise_cond,
			@Param(value=StrategyValueAverage.FELL_RATE, required=false,	desc="下跌比率") Double fell_rate,
			@Param(value=StrategyValueAverage.FELL_AMOUNT, required=false,	desc="下跌金额") Double fell_amount,
			@Param(value=StrategyValueAverage.FELL_COND, required=true,	desc="下跌条件", enumClass=TriggerCondition.class) Integer fell_cond
		) throws Exception {
		if(rise_cond == TriggerCondition.AMOUNT.value() && rise_amount == null) {
			throw new AppException("0101","上涨金额不能空！");
		}
		if(rise_cond == TriggerCondition.RATE.value() && rise_rate == null) {
			throw new AppException("0101","上涨比率不能空！");
		}
		if(rise_amount == null || rise_rate == null) {
			throw new AppException("0101","上涨金额和比率不能空！");
		}
		if(fell_cond == TriggerCondition.AMOUNT.value() && fell_amount == null) {
			throw new AppException("0101","下跌金额不能空！");
		}
		if(fell_cond == TriggerCondition.RATE.value() && fell_rate == null) {
			throw new AppException("0101","下跌比率不能空！");
		}
		if(fell_amount == null || fell_rate == null) {
			throw new AppException("0101","下跌金额和比率不能空！");
		}
		if(rise_rate != null) rise_rate = rise_rate / 100;
		if(fell_rate != null) fell_rate = fell_rate / 100;
		try {
			this.update(strategy_id, target_amount, inflation_rate, rise_amount, rise_rate, rise_cond, fell_rate, fell_amount, fell_cond);
		} catch (Exception e) {
			e.printStackTrace();
			this.create(strategy_id, target_amount, inflation_rate, rise_amount, rise_rate, rise_cond, fell_rate, fell_amount, fell_cond);
		}
		this.flushDetails(strategy_id);
		return ModelFactory.create(ActionResult.class, Codes.CODE, Codes.SUCCESS);
	}

	@MethodInfo("删除")
	@DaoRemove(entity=StrategyValueAverage.ENTITY_NAME)
	public ActionResult remove(
			@Param(value=StrategyValueAverage.STRATEGY_ID, required=true,	desc="策略ID") Long strategy_id
		) {
		this.detailService.removeByStrategyId(strategy_id);
		return null;
	}

	@MethodInfo("搜索")
	@DaoQuery(entity=StrategyValueAverage.ENTITY_NAME, pageable=true, modelClass=StrategyValueAverage.class)
	public QueryResult<StrategyValueAverage> findAll(
			@Param(value=Codes.PAGE_NUM, 	required=false, desc="分页页号，默认0") int page,
			@Param(value=Codes.PAGE_SIZE, 	required=false, desc="分页大小，默认10") int rows) throws Exception {
		return null;
	}

	@SuppressWarnings("unchecked")
	@MethodInfo("查询")
	@DaoQuery(entity=StrategyValueAverage.ENTITY_NAME, single=true, throwsNotFoundException=true )
	public StrategyValueAverage findById(
			@Param(value=StrategyValueAverage.STRATEGY_ID, required=true,	desc="策略ID") Long strategy_id
		) {
		return null;
	}
	//

	@Override
	@Transaction
	public ActionResult executeStrategy(
			@Param(value=StrategyGrid.STRATEGY_ID, required=true,	desc="策略ID") Long strategy_id) {
		StrategyValueAverage sv = this.findById(strategy_id);
		Strategy s = this.strategyService.findById(strategy_id);
		Investment v = this.investService.findById(s.getInvestId());
		if(s.getBatchNum() == null) s.setBatchNum(0);
		Integer batch_num = s.getBatchNum();
		Date from_date = new Date();
		Date to_date = DateUtils.add(from_date, Field.DATE, 5);
		//根据年通胀计算目标金额
		Double inflation_amount = .0;
		if(sv.getInflationRate() != null && sv.getInflationRate() >0 ) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(new Date());
			int days = cal.get(Calendar.DAY_OF_YEAR);
			inflation_amount = sv.getTargetAmount() * sv.getInflationRate() * days/365;
		}
		//
		if(sv.getFellAmount() == null) sv.setFellAmount(0.0);
		if(sv.getFellRate() == null) sv.setFellRate(0.0);
		if(sv.getRiseAmount() == null) sv.setRiseAmount(0.0);
		if(sv.getRiseRate() == null) sv.setRiseRate(0.0);
		final DecimalFormat nf = new DecimalFormat("0000.00");
		if(v.getAmount() > sv.getTargetAmount()) {	//市值大于目标设定,判定并生成卖盘
			//当日已经创建卖出建议则不再继续
			List<InvestmentSuggestion> latestSuggestions = this.suggestionService.findByStrategyId(strategy_id, null).getRows();
			final boolean exists = latestSuggestions.stream().anyMatch(suggestion -> 
				suggestion.getTransactionType() == TransactionType.SELL.value() && 
				(suggestion.getStatus() == InvestmentSuggestion.Status.ORDERED.value() || 
					suggestion.getStatus() == InvestmentSuggestion.Status.PREPARING.value()));
			if(exists) {
				return ModelFactory.create(ActionResult.class, Codes.CODE, Codes.SUCCESS);
			}
			//根据条件创建
			Double amount = v.getAmount() - sv.getTargetAmount() - inflation_amount;	//升值部分
			Double rate = amount / sv.getTargetAmount();
			Invest inv = new Invest(amount, v.getPrice(), 100.0);
			if(sv.getRiseCond() == TriggerCondition.AMOUNT.value() && amount > sv.getRiseAmount()) {
				batch_num ++;
				String remarks = "当前市值：["+v.getAmount()+"]，目标市值：["+sv.getTargetAmount()+"]，时间成本：["+inflation_amount+"]，"+
						"额度["+nf.format(amount)+"]超出设定["+sv.getRiseAmount()+"]，建议卖出！";
				this.suggestionService.create(v.getUserId(), v.getInvestId(), strategy_id, batch_num, v.getAssetsName(), remarks, null, 
						TransactionType.SELL.value(), inv.getAmount(), inv.getQuantity(), from_date, to_date, null, "system", new Date());
			} else if(sv.getRiseCond() == TriggerCondition.RATE.value() && rate > sv.getRiseRate()) {
				batch_num ++;
				String remarks = "当前市值：["+v.getAmount()+"]，目标市值：["+sv.getTargetAmount()+"]，时间成本：["+inflation_amount+"]，"+
						"比率["+nf.format(rate*100)+"%]超出设定["+sv.getRiseRate()*100+"%]，建议卖出！";
				this.suggestionService.create(v.getUserId(), v.getInvestId(), strategy_id, batch_num, v.getAssetsName(), remarks, null, 
						TransactionType.SELL.value(), inv.getAmount(), inv.getQuantity(), from_date, to_date, null, "system", new Date());
			} else if(sv.getRiseCond() == TriggerCondition.AMOUNT_OR_RATE.value() && (amount > sv.getRiseAmount() || rate > sv.getRiseRate())) {
				batch_num ++;
				String remarks = "当前市值：["+v.getAmount()+"]，目标市值：["+sv.getTargetAmount()+"]，时间成本：["+inflation_amount+"]，"+
						"比率["+nf.format(rate*100)+"%]超出设定["+sv.getRiseRate()*100+"%]或者额度["+nf.format(amount)+"]超出设定["+sv.getRiseAmount()+"]，建议卖出！";
				this.suggestionService.create(v.getUserId(), v.getInvestId(), strategy_id, batch_num, v.getAssetsName(), remarks, null, 
						TransactionType.SELL.value(), inv.getAmount(), inv.getQuantity(), from_date, to_date, null, "system", new Date());
			} else if(sv.getRiseCond() == TriggerCondition.AMOUNT_AND_RATE.value() && amount > sv.getRiseAmount() && rate > sv.getRiseRate()) {
				batch_num ++;
				String remarks = "当前市值：["+v.getAmount()+"]，目标市值：["+sv.getTargetAmount()+"]，时间成本：["+inflation_amount+"]，"+
						"比率["+nf.format(rate*100)+"%]超出设定["+sv.getRiseRate()*100+"%]并且额度["+nf.format(amount)+"]超出设定["+sv.getRiseAmount()+"]，建议卖出！";
				this.suggestionService.create(v.getUserId(), v.getInvestId(), strategy_id, batch_num, v.getAssetsName(), remarks, null, 
						TransactionType.SELL.value(), inv.getAmount(), inv.getQuantity(), from_date, to_date, null, "system", new Date());
			}
		} else if(v.getAmount() < sv.getTargetAmount()) {  //下跌买入
			//当日已经创建卖出建议则不再继续
			List<InvestmentSuggestion> latestSuggestions = this.suggestionService.findByStrategyId(strategy_id, null).getRows();
			final boolean exists = latestSuggestions.stream().anyMatch(suggestion -> 
				suggestion.getTransactionType() == TransactionType.BUY.value() && 
				(suggestion.getStatus() == InvestmentSuggestion.Status.ORDERED.value() || 
					suggestion.getStatus() == InvestmentSuggestion.Status.PREPARING.value()));
			if(exists) {
				return ModelFactory.create(ActionResult.class, Codes.CODE, Codes.SUCCESS);
			}
			//根据条件创建
			Double amount = sv.getTargetAmount() - v.getAmount();	//升值部分
			Double rate = amount / sv.getTargetAmount();
			Invest inv = new Invest(amount, v.getPrice() == null?1.0:v.getPrice(), 100.0);
			if(sv.getFellCond() == TriggerCondition.AMOUNT.value() && amount > sv.getFellAmount()) {
				batch_num ++;
				String remarks = "当前市值：["+v.getAmount()+"]，目标市值：["+sv.getTargetAmount()+"],"+
						"额度["+nf.format(amount)+"]超出设定["+sv.getFellAmount()+"]，建议买入！";
				this.suggestionService.create(v.getUserId(), v.getInvestId(), strategy_id, batch_num, v.getAssetsName(), remarks, null, 
						TransactionType.BUY.value(), inv.getAmount(), inv.getQuantity(), from_date, to_date, null, "system", new Date());
			} else if(sv.getFellCond() == TriggerCondition.RATE.value() && rate > sv.getFellRate()) {
				batch_num ++;
				String remarks = "当前市值：["+v.getAmount()+"]，目标市值：["+sv.getTargetAmount()+"],"+
						"比率["+nf.format(rate*100)+"%]超出设定["+sv.getFellRate()*100+"%]，建议买入！";
				this.suggestionService.create(v.getUserId(), v.getInvestId(), strategy_id, batch_num, v.getAssetsName(), remarks, null, 
						TransactionType.BUY.value(), inv.getAmount(), inv.getQuantity(), from_date, to_date, null, "system", new Date());
			} else if(sv.getFellCond() == TriggerCondition.AMOUNT_OR_RATE.value() && (amount > sv.getFellAmount() || rate > sv.getFellRate())) {
				batch_num ++;
				String remarks = "当前市值：["+v.getAmount()+"]，目标市值：["+sv.getTargetAmount()+"],"+
						"比率["+nf.format(rate*100)+"%]超出设定["+sv.getFellRate()*100+"%]或者额度["+nf.format(amount)+"]超出设定["+sv.getFellAmount()+"]，建议买入！";
				this.suggestionService.create(v.getUserId(), v.getInvestId(), strategy_id, batch_num, v.getAssetsName(), remarks, null, 
						TransactionType.BUY.value(), inv.getAmount(), inv.getQuantity(), from_date, to_date, null, "system", new Date());
			} else if(sv.getFellCond() == TriggerCondition.AMOUNT_AND_RATE.value() && amount > sv.getFellAmount() && rate > sv.getFellRate()) {
				batch_num ++;
				String remarks = "当前市值：["+v.getAmount()+"]，目标市值：["+sv.getTargetAmount()+"],"+
						"比率["+nf.format(rate*100)+"%]超出设定["+sv.getFellRate()*100+"%]并且额度["+nf.format(amount)+"]超出设定["+sv.getFellAmount()+"]，建议买入！";
				this.suggestionService.create(v.getUserId(), v.getInvestId(), strategy_id, batch_num, v.getAssetsName(), remarks, null, 
						TransactionType.BUY.value(), inv.getAmount(), inv.getQuantity(), from_date, to_date, null, "system", new Date());
			}
		}
		return ModelFactory.create(ActionResult.class, Codes.CODE, Codes.SUCCESS);
	}
	
	@Override
	@Transaction
	public ActionResult flushDetails(
			@Param(value=StrategyGrid.STRATEGY_ID, required=true,	desc="策略ID") Long strategy_id) {
		StrategyValueAverage sv = this.findById(strategy_id);
		Strategy s = this.strategyService.findById(strategy_id);
		Investment v = this.investService.findById(s.getInvestId());
		this.detailService.removeByStrategyId(strategy_id);
		
		Double inflation_amount = .0;
		if(sv.getInflationRate() != null && sv.getInflationRate() >0 ) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(new Date());
			int days = cal.get(Calendar.DAY_OF_YEAR);
			inflation_amount = sv.getTargetAmount() * sv.getInflationRate() * days/365;
		}
		//买入策略
		if(sv.getFellAmount() == null) sv.setFellAmount(0.0);
		if(sv.getFellRate() == null) sv.setFellRate(0.0);
		if(sv.getRiseAmount() == null) sv.setRiseAmount(0.0);
		if(sv.getRiseRate() == null) sv.setRiseRate(0.0);
		if(sv.getFellCond() != null) {
			Double fell_target_amount = 0.0;
			if(sv.getFellCond() == TriggerCondition.AMOUNT.value()) {
				fell_target_amount = sv.getTargetAmount() - sv.getFellAmount();
			} else if(sv.getFellCond() == TriggerCondition.RATE.value()) {
				fell_target_amount = sv.getTargetAmount() * (1 - sv.getFellRate());
			} else if(sv.getFellCond() == TriggerCondition.AMOUNT_OR_RATE.value()) {
				fell_target_amount = Math.min(sv.getTargetAmount() - sv.getFellAmount(), sv.getTargetAmount() * (1 - sv.getFellRate()));
			} else if(sv.getFellCond() == TriggerCondition.AMOUNT_AND_RATE.value()) {
				fell_target_amount = Math.max(sv.getTargetAmount() - sv.getFellAmount(), sv.getTargetAmount() * (1 - sv.getFellRate()));
			}
			//
			if(v.getQuantity() == null || v.getQuantity() == 0) {
				v.setQuantity(sv.getTargetAmount() / v.getPrice());
			}
			Double q = v.getQuantity();
			Double target_price = fell_target_amount / q;
			//
			Invest inv = new Invest(sv.getTargetAmount() - fell_target_amount, target_price, 100.0);
			this.detailService.create(v.getUserId(), s.getTypeId(), v.getInvestId(), strategy_id, 
					fell_target_amount, inflation_amount, TransactionType.BUY.value(), 
					sv.getTargetAmount() - fell_target_amount, (sv.getTargetAmount() - fell_target_amount) / sv.getTargetAmount(), 
					inv.getAmount(), target_price, inv.getQuantity(), null);
		}
		if(sv.getRiseCond() != null) {
			Double rise_target_amount = 0.0;
			if(sv.getRiseCond() == TriggerCondition.AMOUNT.value()) {
				rise_target_amount = sv.getTargetAmount() + sv.getRiseAmount();
			} else if(sv.getRiseCond() == TriggerCondition.RATE.value()) {
				rise_target_amount = sv.getTargetAmount() * (1 + sv.getRiseRate());
			} else if(sv.getRiseCond() == TriggerCondition.AMOUNT_OR_RATE.value()) {
				rise_target_amount = Math.max(sv.getTargetAmount() + sv.getRiseAmount(), sv.getTargetAmount() * (1 + sv.getRiseRate()));
			} else if(sv.getRiseCond() == TriggerCondition.AMOUNT_AND_RATE.value()) {
				rise_target_amount = Math.min(sv.getTargetAmount() + sv.getRiseAmount(), sv.getTargetAmount() * (1 + sv.getRiseRate()));
			}
			//
			if(v.getQuantity() == null || v.getQuantity() == 0) {
				v.setQuantity(sv.getTargetAmount() / v.getPrice());
			}
			Double q = v.getQuantity();
			Double target_price = rise_target_amount / q;
			//
			Invest inv = new Invest(rise_target_amount - sv.getTargetAmount(), target_price, 100.0);
			this.detailService.create(v.getUserId(), s.getTypeId(), v.getInvestId(), strategy_id, 
					rise_target_amount, inflation_amount, TransactionType.SELL.value(), 
					sv.getTargetAmount() - rise_target_amount, (sv.getTargetAmount() - rise_target_amount) / sv.getTargetAmount(), 
					inv.getAmount(), target_price, inv.getQuantity(), null);
		}
		return ModelFactory.create(ActionResult.class, Codes.CODE, Codes.SUCCESS);
	}
	
}